home *** CD-ROM | disk | FTP | other *** search
/ Aminet 8 / Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso / Aminet / comm / tcp / netinput37_3.lha / NetInput / source / unixsem.c < prev    next >
C/C++ Source or Header  |  1995-04-26  |  4KB  |  148 lines

  1. /*
  2. ** $VER: unixsem.c 1.0 (05 Mar 95)
  3. **
  4. ** UNIX like counting semaphores for the AMIGA
  5. **
  6. ** (C) Copyright 1995 Marius Gröger
  7. **     All Rights Reserved
  8. **
  9. ** $HISTORY:
  10. **
  11. ** 05 Mar 1995 : 001.000 :  created
  12. */
  13.  
  14. #ifndef CLIB_ALIB_PROTOS_H
  15. #include <clib/alib_protos.h>
  16. #endif
  17. #ifndef CLIB_EXEC_PROTOS_H
  18. #include <clib/exec_protos.h>
  19. #include <pragmas/exec_pragmas.h>
  20. #endif
  21.  
  22. #include "unixsem.h"
  23.  
  24. /* private structure to maintain tasks within the waiting space of a semaphore */
  25. struct semachain
  26. {
  27.    struct MinNode link;    /* std exec minimal node */
  28.    struct Task *this;      /* the task waiting to get granted a semaphore unit */
  29.    ULONG sigmask;          /* the task waits for this exec signal */
  30. };
  31.  
  32. /* Initialize a semaphore for use. This sets various private fields.
  33.    The user may provide an Exec style signal-mask which should be used
  34.    for waiting operertions concerning THIS semaphore. If signal is
  35.    equal to -1, the default signal-mask UNIXSEM_SIGMASK is used. This
  36.    is defined in "unixsem.h" and may be altered with succeeding recompilation
  37.    of ALL modules using the semaphore calls.
  38.    The unit counter is set to zero.
  39. */
  40. extern VOID
  41.    sinit(
  42.       CountSemaphore *sem     /* pointer to a semaphore */,
  43.       ULONG sigmask           /* exec signal-mask to be used for waiting
  44.                                  operations or -1 to used UNIXSEM_SIGMASK */
  45.       )
  46. {
  47.    InitSemaphore(&sem->sem_Lock);
  48.    NewList((struct List*)&sem->sem_WaitingSpace);
  49.    sem->sem_Count = 0;
  50.    sem->sem_SigMask = (sigmask != (ULONG)(-1)) ? sigmask : UNIXSEM_SIGMASK;
  51. }
  52.  
  53. /* Set a semaphore to a certain value. This is done independent of
  54.    any task possibly waiting fo the semaphore. Therefore this function
  55.    should only be called prior to any call of ssignal() or swait().
  56.    To create a mutual exclusion semaphore for protected areas of code,
  57.    te following sequence is appropriate:
  58.  
  59.       sinit(&mutex,-1);
  60.       sset(&mutex,1);
  61.  
  62.    Anybody who wants to enter the protected area later should
  63.    perform these steps:
  64.  
  65.       swait(&mutex);
  66.       // protected area here
  67.       ssignal(&mutex);
  68.  
  69.    This has, of course, the same result as an according ObainSemaphore()/
  70.    ReleaseSemaphore() construct, but might be useful when porting UNIX
  71.    applications.
  72. */
  73. extern VOID sset(
  74.       CountSemaphore *sem     /* pointer to a semaphore */,
  75.       LONG val                /* value the semaphore should be assigned */
  76.       )
  77. {
  78.    /* always single-threaden the semaphore access */
  79.    ObtainSemaphore(&sem->sem_Lock);
  80.    sem->sem_Count = val;
  81.    ReleaseSemaphore(&sem->sem_Lock);
  82. }
  83.  
  84. /* Increment the unit counter of a semaphore. If there are any tasks waiting
  85.    for a unit, the chronologically first waiter will be awakened.
  86. */
  87. extern VOID ssignal(
  88.       CountSemaphore *sem     /* pointer to a semaphore */
  89.       )
  90. {
  91.    struct semachain *sc;
  92.  
  93.    /* always single-threaden the semaphore access */
  94.    ObtainSemaphore(&sem->sem_Lock);
  95.  
  96.    /* add a unit, have to wake up somebody ? */
  97.    if (sem->sem_Count++ < 0)
  98.    {
  99.       /* there MUST be at least one waiter! */
  100.       sc = (struct semachain*)RemHead((struct List*)&sem->sem_WaitingSpace);
  101.       Signal(sc->this, sc->sigmask);
  102.    }
  103.  
  104.    ReleaseSemaphore(&sem->sem_Lock);
  105. }
  106.  
  107. /* Decrement the unit count of a semaphore. If the unit count before the
  108.    call to swait() was less or equal to zero, the task will be added
  109.    to the semaphore's waiting space and fall asleep until sombody
  110.    calls ssignal() to the semaphore. If there are already other tasks
  111.    within the waiting space, these will be waked up first, before your
  112.    task is.
  113. */
  114.  
  115. extern VOID swait(
  116.       CountSemaphore *sem     /* pointer to a semaphore */
  117.       )
  118. {
  119.    struct semachain sc;
  120.    BOOL sleep;
  121.  
  122.    ObtainSemaphore(&sem->sem_Lock);
  123.    /* get a unit, go to sleep ? */
  124.    if (--sem->sem_Count < 0)
  125.    {
  126.       /* delay the Wait() till after ReleaseSemaphore() */
  127.       sleep = TRUE;
  128.       sc.sigmask = sem->sem_SigMask;
  129.       sc.this = FindTask(NULL);
  130.       AddTail((struct List*)&sem->sem_WaitingSpace, (struct Node*)&sc.link);
  131.    }
  132.    else
  133.    {
  134.       sleep = FALSE;
  135.    }
  136.    ReleaseSemaphore(&sem->sem_Lock);
  137.  
  138.    /*
  139.    ** Note: maybe we are now de-queued again by a concurrent ssignal()
  140.    ** and got the exec-signal before we Wait() for it. This is ok.
  141.    ** Fortunatly, it is not possible for us to have more than
  142.    ** one semachain pending, as this would be a bit trickier to
  143.    ** handle (exec signals do not nest).
  144.    */
  145.    if (sleep) Wait(sem->sem_SigMask);
  146. }
  147.  
  148.